// 特性：
// - 函数 返回自身，链式调用
// - 构造函数是宏队列，then后是微队列，已敲定后不能再改
// - 1、静态方法：all,allSettled,any,race,resolve,reject
// - all 都是成功返回数组给then，或者有一个失败就都终止且返回错误给catch
// - allSettled 都已敲定状态，有成功有失败，数组返回给then
// - any 任意一个成功就终止，返回给then
// - race 任意一个已敲定就终止， 成功返回给then，失败返回给catch
// - 2、实例方法 then,catch,finally
function Promise(callback) {
  if (!this instanceof Promise) {
    return console.error('must call by new Promise')
  }
  if (typeof callback != 'function') {
    return console.error('need callback function')
  }
  if (callback instanceof Promise) {
    return callback
  }
  this.status = 'PENDING'
  const resolve = value => {
    if (this.status != 'PENDING') return
    this.status = 'FULFILLED'
    this.value = value
    setTimeout(() => {
      this.resolveFn?.(value)
    })
  }
  const reject = reason => {
    if (this.status != 'PENDING') return
    this.status = 'REJECTED'
    this.reason = reason
    setTimeout(() => {
      this.rejectFn?.(reason)
    })
  }
  try {
    callback(resolve, reject)
  } catch (e) {
    reject(e)
  }
}
Promise.prototype.then = function (resolve, reject) {
  return new Promise((nextResolve, nextReject) => {
    resolve = resolve || Promise.resolve
    reject = reject || Promise.reject
    nextResolve = nextResolve || Promise.resolve
    nextReject = nextReject || Promise.reject

    const handler = result => {
      if (result instanceof Promise) {
        if (result.status == 'FULFILLED') {
          nextResolve(result.value)
        }
        if (result.status == 'REJECTED') {
          nextReject(result.reason)
        }
      }
      nextResolve(result)
    }

    this.resolveFn = value => {
      const result = resolve(value)
      handler(result)
    }
    this.rejectFn = reason => {
      const result = reject(reason)
      handler(result)
    }
  })
}
Promise.prototype.catch = function (reject) {
  return this.then(null, reject)
}
Promise.prototype.finally = function (fn) {
  const newFn = () => fn()
  return this.then(newFn, newFn)
}
Promise.all = function (array) {
  return new Promise((resolve, reject) => {
    const obj = Object.create(null)
    array.forEach((it, index) => {
      it.then(
        value => {
          obj[index] = value
          if (Object.keys(obj).length == array.length) {
            resolve(Object.values(obj))
          }
        },
        reason => {
          reject(reason)
        }
      )
    })
  })
}
Promise.allSettled = function (array) {
  return new Promise((resolve, reject) => {
    const obj = Object.create(null)
    array.forEach((it, index) => {
      it.then(
        value => {
          obj[index] = value
          if (Object.keys(obj).length == array.length) {
            resolve(Object.values(obj))
          }
        },
        reason => {
          obj[index] = reason
          if (Object.keys(obj).length == array.length) {
            reject(Object.values(obj))
          }
        }
      )
    })
  })
}
Promise.any = function (array) {
  return new Promise(resolve => {
    array.forEach(it => {
      it.then(value => {
        resolve(value)
      })
    })
  })
}
Promise.race = function (array) {
  return new Promise((resolve, reject) => {
    array.forEach((it, index) => {
      it.then(
        value => {
          resolve(value)
        },
        reason => {
          reject(reason)
        }
      )
    })
  })
}
Promise.resolve = function (value) {
  return new Promise(resolve => {
    resolve(value)
  })
}
Promise.reject = function (reason) {
  return new Promise((_, reject) => {
    reject(reason)
  })
}

// new Promise(resolve => {
//     resolve(1)
// }).then(a => a + 1).then(a => a + 1).then(a => a + 1).then(console.log)

// Promise.reject(1)
//     .then(a => a + 1)
//     .then(a => a + 1)
//     .catch(a => {
//         console.log(a)
//         return a
//     })
//     .then(a => a + 1)
//     .then(a => {
//         console.log(a)
//         return Promise.reject(a)
//     })
//     .catch(console.log)
//     .catch(console.log)
//     .then(console.log)
//     .finally(() => console.log('fi'))

// Promise.all([Promise.reject(1), Promise.resolve(2)]).then(console.log).catch(console.log)
// Promise.allSettled([Promise.reject(1), Promise.resolve(2)]).then(console.log).catch(console.log)
// Promise.any([Promise.reject(1), Promise.resolve(2)]).then(console.log).catch(console.log)
// Promise.race([Promise.reject(1), Promise.resolve(2)]).then(console.log).catch(console.log)
